package beastick.configurator;

//tofigurator Open Source Project
//
//Copyright 2008 Tofig Kareemov, estereos@gmail.com
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Properties;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import beastick.configurator.types.CParameterizedString;
import beastick.configurator.types.CTypedMap;
import beastick.security.generic.SecureGUID;
import beastick.utility.CMatcher;
import beastick.utility.CSimpleXML;
import beastick.utility.CUtilityMethods;

public class CConfigurator extends CUtilityMethods
{
 public final static int I_EXPORT_FILE_TYPE_LIST        = 0;
 public final static int I_EXPORT_FILE_TYPE_HIERARCHY   = 1;
 private String          oInstanceID                    = new SecureGUID()
                                                          .toStringABC();
 private String          sPrivateParamPrefix            = "0." + oInstanceID
                                                          + ".private.";
 private Hashtable       oConfiguration                 = new Hashtable();
 private Hashtable       oConvertersTable               = new Hashtable();
 private String          S_XMLTAG_CONFIGURATION         = "configuration";
 private String          S_XMLTAG_IMPORT                = "import";
 private String          S_XMLTAG_FILE                  = "file";
 private String          S_XMLTAG_SILENTLY              = "silently";
 private String          S_XMLTAG_NAME                  = "name";
 private String          S_XMLTAG_PACKAGE               = "package";
 private String          S_XMLTAG_CLASS                 = "class";
 private String          S_XMLTAG_INSTANCE              = "instance";
 private String          S_XMLTAG_PARAM                 = "param";
 private String          S_XMLTAG_VALUE                 = "value";
 private String          S_XMLTAG_VALUEOF               = "valueof";
 private String          S_XMLTAG_ARRAY                 = "array";
 private String          S_XMLTAG_ARRAY_APPEND          = "append";
 private String          S_XMLTAG_ARRAY_ITEM            = "item";
 private String          S_XMLTAG_IFBLOCK               = "if";
 private String          S_SET_VALUE_COMMAND_PARAM_NAME = "%THIS_PARAM_FULL_NAME%";
 private String          sLoadedFileName                = "";
 private DateFormat      oDateFormat                    = DateFormat
                                                          .getDateTimeInstance(
                                                            DateFormat.DEFAULT,
                                                            DateFormat.DEFAULT,
                                                            Locale.getDefault());
 private boolean         bWorkSilently                  = false;
 private String          sThisClassName                 = this.getClass()
                                                          .getName();

 public CConfigurator()
 {
  Init();
 }

 public CConfigurator(Hashtable ioConfiguration)
 {
  Init();
  oConfiguration = ioConfiguration;
 }

 private void Log(String sValue)
 {
  if (!bWorkSilently)
  {
   System.out.println(sValue);
  }
 }

 public void Load(String isFileName)
 {
  Load(isFileName, false);
 }

 public void Load(String isFileName, boolean bSilently)
 {
  // oConfiguration.clear();
  LoadFromSystemProperties();
  if (CUtilityMethods.IsValuable(isFileName))
   LoadFromXML(isFileName, bSilently);
  sLoadedFileName = isFileName;
 }

 public void LoadFromXMLString(String sXML, boolean bSilently)
 {
  LoadFromSystemProperties();
  if (CUtilityMethods.IsValuable(sXML))
  {
   CSimpleXML oXML = new CSimpleXML();
   Node oRoot = oXML.GetXMLRootNodeLoadedFromXMLString(sXML, bSilently
     || bWorkSilently);
   if (oRoot == null)
   {
    SetPrivateValueAsString("ImportedFile." + "XML_String",
      "loading failed (file not found or contains xml errors)");
   } else if (!oRoot.getNodeName().equalsIgnoreCase(S_XMLTAG_CONFIGURATION))
   {
    SetPrivateValueAsString("ImportedFile." + "XML_String",
      "loading failed (wrong xml configuration file format)");
   } else
   {
    SetPrivateValueAsString("ImportedFile." + "XML_String", "loaded at "
      + System.currentTimeMillis());
    ProcessXMLNode(oXML, oRoot, "", 0, bSilently);
   }
  }
  sLoadedFileName = "XML_String";
 }

 public String getLoadedFileName()
 {
  return sLoadedFileName;
 }

 public void LoadFromSystemProperties()
 {
  Properties oProperties = System.getProperties();
  Enumeration oEnumeration = oProperties.propertyNames();
  String sPropertyName = "";
  String sPropertyValue = "";
  for (; oEnumeration.hasMoreElements();)
  {
   sPropertyName = (String) oEnumeration.nextElement();
   sPropertyValue = oProperties.getProperty(sPropertyName);
   sPropertyName = "system.property." + sPropertyName;
   SetValueAsString(sPropertyName, sPropertyValue);
  }
 };

 private void LoadFromXML(String isFileName, boolean bSilently)
 {
  if (IsValuable(GetPrivateValueAsString("ImportedFile." + isFileName)))
  {
   SetPrivateValueAsString("ImportedFile." + isFileName,
     "trying to double import at " + System.currentTimeMillis());
   return;
  }
  CSimpleXML oXML = new CSimpleXML();
  Node oRoot = oXML
    .GetXMLRootNodeLoaded(isFileName, bSilently || bWorkSilently);
  if (oRoot == null)
  {
   SetPrivateValueAsString("ImportedFile." + isFileName,
     "loading failed (file not found or contains xml errors)");
  } else if (!oRoot.getNodeName().equalsIgnoreCase(S_XMLTAG_CONFIGURATION))
  {
   SetPrivateValueAsString("ImportedFile." + isFileName,
     "loading failed (wrong xml configuration file format)");
  } else
  {
   SetPrivateValueAsString("ImportedFile." + isFileName, "loaded at "
     + System.currentTimeMillis());
   ProcessXMLNode(oXML, oRoot, "", 0, bSilently);
  }
 }

 public void Reload()
 {
  if (IsValuable(sLoadedFileName))
  {
   CConfigurator oTempConfiguration = new CConfigurator();
   oTempConfiguration.Load(sLoadedFileName);
   Enumeration oKeys = oTempConfiguration.oConfiguration.keys();
   for (; oKeys.hasMoreElements();)
   {
    String sKey = oKeys.nextElement().toString();
    if (!IsPrivateParameter(sKey))
    {
     SetValueAsString(sKey, oTempConfiguration.GetValueAsString(sKey));
     oTempConfiguration.RemoveParameter(sKey);
    }
   }
   //
   //      
   //      
   // CleanImportedFileRecords();
   // Load(sLoadedFileName);
  }
 }

 public Object GetValueAsObject(Object ooObject, String sParameterName)
 {
  if ((ooObject == null) || (!IsValuable(sParameterName)))
  {
   return ooObject;
  }
  Class oObjectClass = ooObject.getClass();
  if (oObjectClass.isArray())
  {
   return GetObjectArray(oObjectClass.getComponentType(), sParameterName);
  }
  Object oResult = GetValueAsObjectByTypeName(oObjectClass.getName(),
    sParameterName);
  if (oResult != null)
  {
   return oResult;
  } else
  {
   return ooObject;
  }
 }

 public Object GetValueAsObjectByTypeName(String sType, String sParameterName)
 {
  Object oResult = null;
  if ((!IsValuable(sType)) || (!IsValuable(sParameterName)))
  {
   return oResult;
  }
  Method oConverter = null;
  Object[] oCallerMethodArgs = new Object[1];
  boolean bAccessible = false;
  oCallerMethodArgs[0] = GetValueAsString(sParameterName.replace('$', '.'));
  if (((String) oCallerMethodArgs[0]) != null)
  {
   try
   {
    oConverter = (Method) oConvertersTable.get(sType);
    if (oConverter != null)
    {
     oResult = (Object) (oConverter.invoke(this, oCallerMethodArgs));
    } else
    {
     Log("WARN. CConfigurator.GetValueAsObject: Converter for " + "\"" + sType
       + "\" not found!");
    }
   } catch (Throwable T)
   {
    Log(T.toString());
   }
  } else
  {
   Log("WARN. CConfigurator.GetValueAsObject: Parameter " + "\""
     + sParameterName + "\" not found!");
  }
  return oResult;
 }

 public Object GetObjectArray(Class oType, String sParameterName)
 {
  Object[] oResult = null;
  try
  {
   oResult = (Object[]) Array.newInstance(oType, Integer
     .parseInt(GetValueAsString(sParameterName.replace('$', '.'))));
   for (int i = 0; i < oResult.length; ++i)
   {
    oResult[i] = GetMemberObject(oType, sParameterName + "." + i);
   }
  } catch (Throwable T)
  {
   Log(T.toString());
  }
  return oResult;
 }

 public Object GetMemberObject(Class oType, String sParameterName)
 {
  Object oResult = null;
  try
  {
   if (oType.isArray())
   {
    return GetObjectArray(oType.getComponentType(), sParameterName);
   }
   oResult = oType.newInstance();
   SetMyFields(oResult);
   SetMyInstanceFieldsExplicitly(oResult, sParameterName);
  } catch (Throwable T)
  {
   Log(T.toString());
  }
  return oResult;
 }

 public String GetValueAsString(String sParameterName)
 {
  return (String) oConfiguration.get(sParameterName);
 }

 public int GetValueAsInt(String sParameterName)
 {
  return ((Integer) GetValueAsObject(new Integer(0), sParameterName))
    .intValue();
 };

 public boolean GetValueAsBoolean(String sParameterName)
 {
  return ((Boolean) GetValueAsObject(new Boolean(false), sParameterName))
    .booleanValue();
 }

 public long GetConfigurationSize()
 {
  return oConfiguration.size();
 }

 public boolean ParameterExists(String sParameter)
 {
  return oConfiguration.containsKey(sParameter);
 }

 public void RemoveParameter(String sParameter)
 {
  oConfiguration.remove(sParameter);
 }

 public void SetValueAsString(String sParameter, String sValue)
 {
  if (sValue.equals(S_SET_VALUE_COMMAND_PARAM_NAME))
  {
   sValue = sParameter;
  }
  boolean bProtection = false;
  if (ParameterExists(sPrivateParamPrefix + sParameter + ".[ReadOnly]"))
  {
   if (GetValueAsBoolean(sPrivateParamPrefix + sParameter + ".[ReadOnly]"))
   {
    bProtection = true;
   }
  }
  if (!bProtection)
  {
   oConfiguration.put(sParameter, sValue);
  }
  if (sParameter.indexOf("system.property.") == 0)
  {
   String sProperty = sParameter.substring("system.property.".length());
   System.setProperty(sProperty, sValue);
  }
 }

 public void SetProtectedValueAsString(String sParameter, String sValue)
 {
  SetPrivateValueAsString(sParameter + ".[ReadOnly]", "false");
  SetValueAsString(sParameter, sValue);
  SetPrivateValueAsString(sParameter + ".[ReadOnly]", "true");
 }

 public String GetPrivateValueAsString(String sParameter)
 {
  return GetValueAsString(sPrivateParamPrefix + sParameter);
 }

 private void SetPrivateValueAsString(String sParameter, String sValue)
 {
  SetValueAsString(sPrivateParamPrefix + sParameter, sValue);
 }

 public boolean IsPrivateParameter(String sParameter)
 {
  return (sParameter.indexOf(sPrivateParamPrefix) == 0);
 }

 public void RemovePrivateParameter(String sParameter)
 {
  RemoveParameter(sPrivateParamPrefix + sParameter);
 }

 private void Init()
 {
  oConfiguration.clear();
  oConvertersTable.clear();
  Class[] oCallerMethodArgTypes =
  { String.class };
  try
  {
   oConvertersTable.put("String", this.getClass().getDeclaredMethod(
     "SimpleStringConverter", oCallerMethodArgTypes));
   oConvertersTable.put(String.class.getName(), this.getClass()
     .getDeclaredMethod("SimpleStringConverter", oCallerMethodArgTypes));
   oConvertersTable.put("boolean", Boolean.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put(Boolean.class.getName(), Boolean.class.getMethod(
     "valueOf", oCallerMethodArgTypes));
   oConvertersTable.put("char", this.getClass().getDeclaredMethod(
     "SimpleCharacterConverter", oCallerMethodArgTypes));
   oConvertersTable.put(Character.class.getName(), this.getClass()
     .getDeclaredMethod("SimpleCharacterConverter", oCallerMethodArgTypes));
   oConvertersTable.put("byte", Byte.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put(Byte.class.getName(), Byte.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put("short", Short.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put(Short.class.getName(), Short.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put("int", Integer.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put(Integer.class.getName(), Integer.class.getMethod(
     "valueOf", oCallerMethodArgTypes));
   oConvertersTable.put("long", Long.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put(Long.class.getName(), Long.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put("double", Double.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put(Double.class.getName(), Double.class.getMethod(
     "valueOf", oCallerMethodArgTypes));
   oConvertersTable.put("float", Float.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put(Float.class.getName(), Float.class.getMethod("valueOf",
     oCallerMethodArgTypes));
   oConvertersTable.put(BigInteger.class.getName(), this.getClass()
     .getDeclaredMethod("SimpleBigIntegerConverter", oCallerMethodArgTypes));
   oConvertersTable.put(Date.class.getName(), this.getClass()
     .getDeclaredMethod("SimpleDateConverter", oCallerMethodArgTypes));
   oConvertersTable.put(CParameterizedString.class.getName(), this.getClass()
     .getDeclaredMethod("SimpleParameterizedStringConverter",
       oCallerMethodArgTypes));
   oConvertersTable.put(CTypedMap.class.getName(), this.getClass()
     .getDeclaredMethod("SimpleTypedMapConverter", oCallerMethodArgTypes));
  } catch (Throwable T)
  {
   Log(T.toString());
  }
 }

 private boolean IsValuableNode(Node oNode)
 {
  boolean bResult = false;
  if (!CUtilityMethods.IsValuable(oNode))
  {
   return bResult;
  }
  String sNodeName = oNode.getNodeName().toLowerCase();
  if (sNodeName.equals(S_XMLTAG_PARAM))
  {
   bResult = true;
  } else if (sNodeName.equals(S_XMLTAG_ARRAY_ITEM))
  {
   bResult = true;
  } else if (sNodeName.equals(S_XMLTAG_ARRAY))
  {
   bResult = true;
  } else if (sNodeName.equals(S_XMLTAG_INSTANCE))
  {
   bResult = true;
  } else if (sNodeName.equals(S_XMLTAG_CLASS))
  {
   bResult = true;
  } else if (sNodeName.equals(S_XMLTAG_PACKAGE))
  {
   bResult = true;
  } else if (sNodeName.equals(S_XMLTAG_IMPORT))
  {
   bResult = true;
  } else if (sNodeName.equals(S_XMLTAG_IFBLOCK))
  {
   bResult = true;
  } else if (sNodeName.equals(S_XMLTAG_CONFIGURATION))
  {
   bResult = true;
  }
  return bResult;
 }

 private int ProcessXMLNodeChilds(CSimpleXML oXML, Node oNode,
   String sParamFullName, boolean bSilently, int iValuableFirstChildIndex)
 {
  NodeList oChildNodeList = oNode.getChildNodes();
  int iChildNodeListLength = oChildNodeList.getLength();
  int iValuableChildIndex = iValuableFirstChildIndex;
  for (int i = 0; i < iChildNodeListLength; ++i)
  {
   if (IsValuableNode(oChildNodeList.item(i)))
   {
    ProcessXMLNode(oXML, oChildNodeList.item(i), sParamFullName,
      iValuableChildIndex, bSilently);
    ++iValuableChildIndex;
   }
  }
  return iValuableChildIndex;
 }

 private void ProcessXMLNode(CSimpleXML oXML, Node oNode, String sClassName,
   int iArrayItemNodeIndex, boolean bSilently)
 {
  if (oNode == null)
  {
   return;
  }
  String sNodeName = oNode.getNodeName().toLowerCase();
  String sParamName = "";
  String sParamValue = "";
  int iChildIndex = 0;
  if (sNodeName.equals(S_XMLTAG_CONFIGURATION))
  {
   ProcessXMLNodeChilds(oXML, oNode, "", bSilently, 0);
  } else if (sNodeName.equals(S_XMLTAG_IMPORT))
  {
   sParamValue = oXML.GetXMLAttribValue(oNode, S_XMLTAG_FILE);
   if (IsValuable(sParamValue))
   {
    sParamValue = CParameterizedString.StringValueOf(sParamValue, this);
    LoadFromXML(sParamValue, oXML.GetXMLAttribValue(oNode, S_XMLTAG_SILENTLY)
      .equals("true")
      || bSilently);
   }
  } else if (sNodeName.equals(S_XMLTAG_IFBLOCK))
  {
   sParamValue = oXML.GetXMLAttribValue(oNode, S_XMLTAG_VALUE);
   if (IsValuable(sParamValue))
   {
    if (sParamValue.trim().toLowerCase().equals("true"))
    {
     ProcessXMLNodeChilds(oXML, oNode, sClassName, bSilently, 0);
    }
   } else
   {
    sParamValue = oXML.GetXMLAttribValue(oNode, S_XMLTAG_PARAM);
    if (IsValuable(sParamValue))
    {
     if (((Boolean) (GetValueAsObject(new Boolean(false), sParamValue)))
       .booleanValue())
     {
      ProcessXMLNodeChilds(oXML, oNode, sClassName, bSilently, 0);
     }
    }
   }
  } else if ((sNodeName.equals(S_XMLTAG_PARAM))
    || (sNodeName.equals(S_XMLTAG_ARRAY_ITEM)))
  {
   if (sNodeName.equals(S_XMLTAG_ARRAY_ITEM))
   {
    sParamName = "" + iArrayItemNodeIndex;
   } else if (sNodeName.equals(S_XMLTAG_PARAM))
   {
    sParamName = oXML.GetXMLAttribValue(oNode, S_XMLTAG_NAME);
   }
   ProcessXMLNodeChilds(oXML, oNode, sClassName + sParamName + ".", bSilently,
     0);
   sParamValue = oXML.GetXMLAttribValue(oNode, S_XMLTAG_VALUEOF);
   if (IsValuable(sParamValue))
   {
    String sLookingParam = sParamValue;
    String sCurrentClassName = "" + sClassName;
    int iLastIndexOfSeparator = 0;
    sParamValue = "";
    for (; IsValuable(sCurrentClassName) && !IsValuable(sParamValue);)
    {
     sParamValue = GetValueAsString(sCurrentClassName + sLookingParam);
     sCurrentClassName = sCurrentClassName.substring(0, sCurrentClassName
       .length() - 1);
     iLastIndexOfSeparator = sCurrentClassName.lastIndexOf('.');
     if (iLastIndexOfSeparator > 0)
     {
      sCurrentClassName = sCurrentClassName.substring(0,
        iLastIndexOfSeparator + 1);
     } else
     {
      sCurrentClassName = "";
     }
    }
    if (!IsValuable(sParamValue))
    {
     sParamValue = GetValueAsString(sLookingParam);
    }
   }
   if (!IsValuable(sParamValue))
   {
    sParamValue = oXML.GetXMLAttribValue(oNode, S_XMLTAG_VALUE);
   }
   if (IsValuable(sParamName))
   {
    sParamName = sClassName + sParamName;
    SetValueAsString(sParamName, sParamValue);
    if (sParamName.indexOf(sThisClassName) == 0)
    {
     SetMyFields(this);
    }
   }
  } else if (sNodeName.equals(S_XMLTAG_ARRAY))
  {
   sParamValue = oXML.GetXMLAttribValue(oNode, S_XMLTAG_ARRAY_APPEND);
   String sArrayName = sClassName
     + oXML.GetXMLAttribValue(oNode, S_XMLTAG_NAME);
   int iInitialArrayIndex = 0;
   if (IsValuable(sParamValue)
     && sParamValue.trim().toLowerCase().equals("true"))
   {
    iInitialArrayIndex = GetValueAsInt(sArrayName);
   }
   SetValueAsString(sArrayName, ""
     + ProcessXMLNodeChilds(oXML, oNode, sArrayName + ".", bSilently,
       iInitialArrayIndex));
  } else if ((sNodeName.equals(S_XMLTAG_CLASS))
    || (sNodeName.equals(S_XMLTAG_PACKAGE))
    || (sNodeName.equals(S_XMLTAG_INSTANCE)))
  {
   ProcessXMLNodeChilds(oXML, oNode, sClassName
     + oXML.GetXMLAttribValue(oNode, S_XMLTAG_NAME) + ".", bSilently, 0);
  }
 }

 public Hashtable GetConfiguration()
 {
  return oConfiguration;
 }

 public void SetMyFields(Object ioCaller)
 {
  if (IsValuable(ioCaller))
  {
   SetMyFieldsTyped(ioCaller, ioCaller.getClass(), null, null);
  }
 }

 public void SetMyInstanceFields(Object ioCaller, String sInstanceName)
 {
  if (IsValuable(ioCaller))
  {
   SetMyFieldsTyped(ioCaller, ioCaller.getClass(), null, null);
   SetMyFieldsTyped(ioCaller, ioCaller.getClass(), sInstanceName, null);
  }
 }

 public void SetMyInstanceFieldsExplicitly(Object ioCaller,
   String sExplicitClassFullName)
 {
  if (IsValuable(ioCaller))
  {
   SetMyFieldsTyped(ioCaller, ioCaller.getClass(), null, null);
   SetMyFieldsTyped(ioCaller, ioCaller.getClass(), null, sExplicitClassFullName);
  }
 }

 private boolean SetFieldTyped(Field oField, Object ioCaller,
   Class ioCallerTypeClass, String sInstanceName,
   String sExplicitClassFullName, String sValue)
 {
  boolean bResult = false;
  if (!IsValuable(oField))
   return bResult;
  String sFieldName = "";
  String sFieldFullName = "";
  Method oConverter = null;
  Object[] oCallerMethodArgs = new Object[1];
  boolean bAccessible = false;
  sFieldName = oField.getName();
  if (IsValuable(sInstanceName))
  {
   sFieldName = sInstanceName + "." + sFieldName;
  }
  if (sValue != null)
  {
   sFieldFullName = sFieldName;
   oCallerMethodArgs[0] = sValue;
  } else if (IsValuable(sExplicitClassFullName))
  {
   sFieldFullName = sExplicitClassFullName.replace('$', '.') + "." + sFieldName;
   oCallerMethodArgs[0] = GetValueAsString(sFieldFullName);
  } else
  {
   sFieldFullName = ioCaller.getClass().getName().replace('$', '.') + "."
     + sFieldName;
   oCallerMethodArgs[0] = GetValueAsString(sFieldFullName);
   if (!IsValuable((String) oCallerMethodArgs[0]))
   {
    sFieldFullName = ioCallerTypeClass.getName().replace('$', '.') + "."
      + sFieldName;
    oCallerMethodArgs[0] = GetValueAsString(sFieldFullName);
   }
  }
  if ((String) oCallerMethodArgs[0] != null)
  {
   try
   {
    if (oField.getType().isArray())
    {
     bAccessible = oField.isAccessible();
     oField.setAccessible(true);
     oField.set(ioCaller, GetObjectArray(oField.getType().getComponentType(),
       sFieldFullName));
     oField.setAccessible(bAccessible);
     bResult = true;
    } else
    {
     oConverter = (Method) oConvertersTable.get(oField.getType().getName());
     if ((ioCaller instanceof Class)
       && !(Modifier.isStatic(oField.getModifiers())))
     {
      oConverter = null;
     } else if (oConverter != null)
     {
      bAccessible = oField.isAccessible();
      oField.setAccessible(true);
      oField.set(ioCaller, (oConverter.invoke(this, oCallerMethodArgs)));
      oField.setAccessible(bAccessible);
      bResult = true;
     } else if (!oField.getType().isInterface()
       && !oField.getType().isPrimitive())
     {
      bAccessible = oField.isAccessible();
      oField.setAccessible(true);
      oField.set(ioCaller, GetMemberObject(oField.getType(), sFieldFullName));
      oField.setAccessible(bAccessible);
      bResult = true;
     }
    }
   } catch (Throwable T)
   {
    Log(T.toString());
   }
  }
  return bResult;
 }

 private void SetMyFieldsTyped(Object ioCaller, Class ioCallerTypeClass,
   String sInstanceName, String sExplicitClassFullName)
 {
  if ((ioCaller == null) || (ioCallerTypeClass == null))
  {
   return;
  }
  int i = 0;
  if (ioCaller instanceof Class)
  {
   ioCallerTypeClass = (Class) ioCaller;
  }
  Class oCallerSuperClass = ioCallerTypeClass.getSuperclass();
  if ((oCallerSuperClass != null) && !(oCallerSuperClass.equals(Class.class))
    && !(oCallerSuperClass.equals(Object.class)))
  {
   SetMyFieldsTyped(ioCaller, oCallerSuperClass, sInstanceName,
     sExplicitClassFullName);
  }
  ;
  Field[] oFields = ioCallerTypeClass.getDeclaredFields();
  for (i = 0; i < oFields.length; ++i)
  {
   SetFieldTyped(oFields[i], ioCaller, ioCallerTypeClass, sInstanceName,
     sExplicitClassFullName, null);
  }
 }

 public boolean SetMySingleField(Object ioCaller, String sFieldName)
 {
  return SetMySingleFieldExplicitly(ioCaller, sFieldName, null);
 }

 public boolean SetMySingleFieldExplicitly(Object ioCaller, String sFieldName,
   String sParameterName)
 {
  boolean bResult = false;
  if ((ioCaller == null) || (!IsValuable(sFieldName)))
  {
   return bResult;
  }
  String sValue = null;
  if (IsValuable(sParameterName))
  {
   sValue = GetValueAsString(sParameterName);
   if (sValue == null)
   {
    return bResult;
   }
  }
  Field oField;
  Class oCallerTypeClass = ioCaller.getClass();
  if (ioCaller instanceof Class)
  {
   oCallerTypeClass = (Class) ioCaller;
  }
  for (; oCallerTypeClass != null;)
  {
   try
   {
    oField = oCallerTypeClass.getDeclaredField(sFieldName);
    if (SetFieldTyped(oField, ioCaller, oCallerTypeClass, null, null, sValue))
    {
     bResult = true;
    }
    ;
    oCallerTypeClass = null;
   } catch (Throwable t)
   {
    oCallerTypeClass = oCallerTypeClass.getSuperclass();
   }
  }
  return bResult;
 }

 private BigInteger SimpleBigIntegerConverter(String sValue)
 {
  return new BigInteger(sValue);
 }

 private Character SimpleCharacterConverter(String sValue)
 {
  return new Character(sValue.charAt(0));
 }

 private Date SimpleDateConverter(String sValue)
 {
  try
  {
   return oDateFormat.parse(sValue);
  } catch (ParseException e)
  {
   return new Date();
  }
 }

 private String SimpleStringConverter(String sValue)
 {
  return sValue;
 }

 private CParameterizedString SimpleParameterizedStringConverter(String sValue)
 {
  return new CParameterizedString(sValue, this);
 }

 private CTypedMap SimpleTypedMapConverter(String sValue)
 {
  return new CTypedMap(sValue, this);
 }

 private void InsertXMLListParameter(CSimpleXML oXML, Node oRootNode,
   String sName, String sValue)
 {
  Node oNode = oXML.CreateConfigurationParameterNode(sName, sValue);
  oRootNode.appendChild(oNode);
 };

 private void InsertXMLHierarchyParameter(CSimpleXML oXML, Node oRootNode,
   String sName, String sValue)
 {
  Node oNode = oRootNode;
  Node oNodePrev = oRootNode;
  String sKey = sName;
  String sSubKey = "";
  if (sKey.indexOf(".") >= 0)
  {
   sSubKey = sKey.substring(0, sKey.indexOf("."));
   sKey = sKey.substring(sKey.indexOf(".") + 1, sKey.length());
  } else if (sKey.length() > 0)
  {
   sSubKey = sKey;
   sKey = "";
  } else
  {
   sSubKey = "";
   sKey = "";
  }
  for (; !sSubKey.equals("");)
  {
   oNode = oXML.GetXMLChildNodeByAttributeValue(oNodePrev, S_XMLTAG_PARAM,
     S_XMLTAG_NAME, sSubKey);
   if (oNode == null)
   {
    if (sKey.equals(""))
    {
     oNode = oXML.CreateConfigurationParameterNode(sSubKey, sValue);
    } else
    {
     oNode = oXML.CreateConfigurationParameterNode(sSubKey, "");
    }
    oNodePrev.appendChild(oNode);
   }
   oNodePrev = oNode;
   sSubKey = "";
   if (sKey.indexOf(".") >= 0)
   {
    if (sSubKey.equals(""))
    {
     sSubKey = sKey.substring(0, sKey.indexOf("."));
    } else
    {
     sSubKey = sSubKey + "." + sKey.substring(0, sKey.indexOf("."));
    }
    sKey = sKey.substring(sKey.indexOf(".") + 1, sKey.length());
   } else if (sKey.length() > 0)
   {
    if (sSubKey.equals(""))
    {
     sSubKey = sKey;
    } else
    {
     sSubKey = sSubKey + "." + sKey;
    }
    sKey = "";
   } else
   {
    sSubKey = "";
    sKey = "";
   }
  }
 };

 public boolean ExportToXMLFile(String[] sIncludePattern,
   String[] sExcludePattern, String sFileName, int iType)
 {
  boolean bResult = false;
  Enumeration oKeys = oConfiguration.keys();
  CSimpleXML oXML = new CSimpleXML();
  Node oRootNode = oXML.GetXMLRootNodeNewCreated(S_XMLTAG_CONFIGURATION);
  String[] sSortedKey = new String[oConfiguration.size()];
  CMatcher oMatcher = new CMatcher();
  boolean bToInclude = false;
  for (int i = 0; oKeys.hasMoreElements(); ++i)
  {
   sSortedKey[i] = oKeys.nextElement().toString();
  }
  java.util.Arrays.sort(sSortedKey, String.CASE_INSENSITIVE_ORDER);
  for (int i = 0; i < sSortedKey.length; ++i)
  {
   bToInclude = oMatcher.PassesFilters(sSortedKey[i], sIncludePattern,
     sExcludePattern);
   if (bToInclude)
   {
    if (iType == I_EXPORT_FILE_TYPE_HIERARCHY)
    {
     InsertXMLHierarchyParameter(oXML, oRootNode, sSortedKey[i],
       (String) GetValueAsObject(new String(), sSortedKey[i]));
    } else
    {
     InsertXMLListParameter(oXML, oRootNode, sSortedKey[i],
       (String) GetValueAsObject(new String(), sSortedKey[i]));
    }
   }
  }
  bResult = oXML.WriteToFile(sFileName);
  return bResult;
 }

 public void ImportFromXMLFile(String isFileName, boolean bSilently)
 {
  String oInstanceIDPrev = oInstanceID;
  oInstanceID = new SecureGUID().toStringABC();
  sPrivateParamPrefix = "0." + oInstanceID + ".private.";
  LoadFromXML(isFileName, bSilently);
  oInstanceID = oInstanceIDPrev;
  sPrivateParamPrefix = "0." + oInstanceID + ".private.";
 }

 public boolean IsTypeConvertible(String sType)
 {
  return oConvertersTable.containsKey(sType);
 }

 private void CleanImportedFileRecords()
 {
  String sParamPrefix = sPrivateParamPrefix + "ImportedFile.";
  Enumeration oKeys = oConfiguration.keys();
  for (; oKeys.hasMoreElements();)
  {
   String sKey = oKeys.nextElement().toString();
   if (sKey.indexOf(sParamPrefix) == 0)
   {
    RemoveParameter(sKey);
   }
  }
 }
}